namespace C1.Win.C1FlexGrid
{
    using System;
    using System.Drawing;
    using System.Windows.Forms;

    internal class GridKbdHandler
    {
        internal KeyActionEnum _actionEnter;
        internal KeyActionEnum _actionTab;
        internal AutoSearchEnum _autoSearch;
        internal double _autoSearchDelay;
        internal Timer _autoSearchTimer;
        internal GridModel _grid;
        internal string _searchBuffer;
        internal C1FlexGridBase _view;
        internal const double AUTOSEARCHDELAY_DEFAULT = 1.0;

        internal GridKbdHandler(C1FlexGridBase view)
        {
            this._view = view;
            this._grid = view._grid;
            this._autoSearchTimer = new Timer();
            this._autoSearchTimer.Tick += new EventHandler(this.TimerTick);
            this._actionEnter = KeyActionEnum.MoveDown;
            this._actionTab = KeyActionEnum.None;
            this.AutoSearchDelay = 1.0;
            this.ResetSearch();
        }

        internal void HandleEditorKey(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                if (this._actionEnter != KeyActionEnum.None)
                {
                    MoveCursorEnum move = (this._actionEnter == KeyActionEnum.MoveAcross) ? (e.Shift ? MoveCursorEnum.CellPrev : MoveCursorEnum.CellNext) : (e.Shift ? MoveCursorEnum.CellUp : MoveCursorEnum.CellDown);
                    this._view.MoveSelection(move, false);
                }
            }
            else
            {
                this.OnKeyDown(e);
            }
        }

        internal bool IsInputKey(Keys keyData)
        {
            keyData &= ~(Keys.Alt | Keys.Control | Keys.Shift);
            switch (keyData)
            {
                case Keys.Tab:
                    return (this._actionTab != KeyActionEnum.None);

                case Keys.Return:
                    return (this._actionEnter != KeyActionEnum.None);

                case Keys.Prior:
                case Keys.Next:
                case Keys.Left:
                case Keys.Up:
                case Keys.Right:
                case Keys.Down:
                case Keys.F2:
                case Keys.F4:
                    return true;
            }
            return false;
        }

        internal bool IsSearching()
        {
            return (this._searchBuffer.Length > 0);
        }

        internal bool OnKeyDown(KeyEventArgs e)
        {
            if (this._view.HasCursor())
            {
                if (e.KeyCode == Keys.F2)
                {
                    return this.StartEditing('\r');
                }
                if ((e.KeyCode == Keys.F4) || (e.Alt && (e.KeyCode == Keys.Down)))
                {
                    int row = this._view.Row;
                    int col = this._view.Col;
                    return ((this._view._editHandler.GetEditorType(row, col) == EditorTypeEnum.DropDown) && this.StartEditing('\r'));
                }
                if (((e.KeyCode == Keys.Down) && this.IsSearching()) && this.SearchCharacter('\0'))
                {
                    return true;
                }
                bool extend = e.Shift && this._view.SelHandler.CanExtend();
                MoveCursorEnum none = MoveCursorEnum.None;
                switch (e.KeyCode)
                {
                    case Keys.Tab:
                        extend = false;
                        none = (this._actionTab == KeyActionEnum.MoveDown) ? (e.Shift ? MoveCursorEnum.CellUp : MoveCursorEnum.CellDown) : (e.Shift ? MoveCursorEnum.CellPrev : MoveCursorEnum.CellNext);
                        break;

                    case Keys.Prior:
                        none = MoveCursorEnum.PageUp;
                        break;

                    case Keys.Next:
                        none = MoveCursorEnum.PageDown;
                        break;

                    case Keys.End:
                        none = e.Control ? MoveCursorEnum.EndDown : MoveCursorEnum.EndRight;
                        break;

                    case Keys.Home:
                        none = e.Control ? MoveCursorEnum.HomeUp : MoveCursorEnum.HomeLeft;
                        break;

                    case Keys.Left:
                        none = e.Control ? MoveCursorEnum.HomeLeft : MoveCursorEnum.CellLeft;
                        break;

                    case Keys.Up:
                        none = e.Control ? MoveCursorEnum.HomeUp : MoveCursorEnum.CellUp;
                        break;

                    case Keys.Right:
                        none = e.Control ? MoveCursorEnum.EndRight : MoveCursorEnum.CellRight;
                        break;

                    case Keys.Down:
                        none = e.Control ? MoveCursorEnum.EndDown : MoveCursorEnum.CellDown;
                        break;
                }
                if (none != MoveCursorEnum.None)
                {
                    this.ResetSearch();
                    this._view.MoveSelection(none, extend);
                    return true;
                }
            }
            return false;
        }

        internal bool OnKeyPress(KeyPressEventArgs e)
        {
            if (this._view.Editor != null)
            {
                Control editor = this._view.Editor;
                editor.Text = editor.Text + e.KeyChar;
                TextBox box = this._view.Editor as TextBox;
                if (box != null)
                {
                    box.SelectionStart = box.Text.Length;
                }
                return true;
            }
            if (this._view.HasCursor())
            {
                if (e.KeyChar == '\x001b')
                {
                    this.ResetSearch();
                    return true;
                }
                if (this.SearchCharacter(e.KeyChar))
                {
                    return true;
                }
                if (this.StartEditing(e.KeyChar))
                {
                    return true;
                }
                if ((e.KeyChar == '\r') && (this._actionEnter != KeyActionEnum.None))
                {
                    MoveCursorEnum move = (this._actionEnter == KeyActionEnum.MoveAcross) ? MoveCursorEnum.CellNext : MoveCursorEnum.CellDown;
                    this._view.MoveSelection(move, false);
                    return true;
                }
            }
            return false;
        }

        internal void ResetSearch()
        {
            this._autoSearchTimer.Enabled = false;
            this._searchBuffer = string.Empty;
            Point cursor = this._view.SelHandler.GetCursor();
            this._view.Invalidate(cursor);
        }

        internal bool SearchCharacter(char key)
        {
            Point cursor = this._view.SelHandler.GetCursor();
            if ((this._autoSearch == AutoSearchEnum.None) || ((key > '\0') && (key < ' ')))
            {
                this.ResetSearch();
                return false;
            }
            if (!this.IsSearching() && (key > ' '))
            {
                this.ResetSearch();
            }
            this._autoSearchTimer.Enabled = false;
            this._autoSearchTimer.Enabled = true;
            if ((key == '\b') && (this._searchBuffer.Length > 0))
            {
                this._searchBuffer = this._searchBuffer.Substring(this._searchBuffer.Length - 1);
            }
            if (key >= ' ')
            {
                this._searchBuffer = this._searchBuffer + key;
            }
            int y = cursor.Y;
            if ((this._searchBuffer.Length == 1) || (key == '\0'))
            {
                y++;
            }
            if ((this._autoSearch == AutoSearchEnum.FromTop) && (key != '\0'))
            {
                y = this._view.Rows.Fixed;
            }
            y = this._view.FindRow(this._searchBuffer, y, cursor.X, false, false, true);
            if (y >= 0)
            {
                this._view.Select(y, cursor.X, true);
                return true;
            }
            if (key == ' ')
            {
                return false;
            }
            this.ResetSearch();
            return true;
        }

        internal bool StartEditing(char key)
        {
            if (((key != '\r') && (key < ' ')) && (key > '\0'))
            {
                return false;
            }
            if (!this._view.AllowEditing || !this._view.HasCursor())
            {
                return false;
            }
            Point cursor = this._view.SelHandler.GetCursor();
            if (!this._view.Cols[cursor.X].AllowEditing)
            {
                return false;
            }
            this.ResetSearch();
            this._view.StartEditing(cursor.Y, cursor.X, key, false);
            return true;
        }

        internal void TimerTick(object sender, EventArgs e)
        {
            this.ResetSearch();
        }

        internal AutoSearchEnum AutoSearch
        {
            get
            {
                return this._autoSearch;
            }
            set
            {
                this._autoSearch = value;
            }
        }

        internal double AutoSearchDelay
        {
            get
            {
                return this._autoSearchDelay;
            }
            set
            {
                this._autoSearchDelay = Math.Max(0.0, value);
                this._autoSearchTimer.Interval = (int) Math.Max((double) 1.0, (double) (value * 1000.0));
            }
        }
    }
}

